package com.proton.carepatchtemp.utils.ble;

import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.content.Context;
import android.text.TextUtils;

import com.apkfuns.logutils.LogUtils;
import com.proton.carepatchtemp.application.VCare;
import com.proton.carepatchtemp.constant.Settings;
import com.proton.carepatchtemp.utils.NumUtils;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

/**
 * Created by Api on 2016/10/8.
 */

public class BlueUtils {

    public static final int ECG_START = 16;
    public static final int ECG_DX = 12;
    public static final int NUM_ECG = 12;
    private static HashMap<Integer, String> serviceTypes = new HashMap();
    //-------------------------------------------
    private static HashMap<Integer, String> charPermissions = new HashMap();
    //-------------------------------------------
    private static HashMap<Integer, String> charProperties = new HashMap();
    //--------------------------------------------------------------------------
    private static HashMap<Integer, String> descPermissions = new HashMap();

    static {
        // Sample Services.
        serviceTypes.put(BluetoothGattService.SERVICE_TYPE_PRIMARY, "PRIMARY");
        serviceTypes.put(BluetoothGattService.SERVICE_TYPE_SECONDARY, "SECONDARY");
    }

    static {
        charPermissions.put(0, "UNKNOW");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ, "READ");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE, "WRITE");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
        charPermissions.put(BluetoothGattCharacteristic.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
    }

    static {

        charProperties.put(BluetoothGattCharacteristic.PROPERTY_BROADCAST, "BROADCAST");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_EXTENDED_PROPS, "EXTENDED_PROPS");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_INDICATE, "INDICATE");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_NOTIFY, "NOTIFY");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_READ, "READ");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_SIGNED_WRITE, "SIGNED_WRITE");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE, "WRITE");
        charProperties.put(BluetoothGattCharacteristic.PROPERTY_WRITE_NO_RESPONSE, "WRITE_NO_RESPONSE");
    }

    static {
        descPermissions.put(0, "UNKNOW");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ, "READ");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED, "READ_ENCRYPTED");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_READ_ENCRYPTED_MITM, "READ_ENCRYPTED_MITM");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE, "WRITE");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED, "WRITE_ENCRYPTED");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_ENCRYPTED_MITM, "WRITE_ENCRYPTED_MITM");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED, "WRITE_SIGNED");
        descPermissions.put(BluetoothGattDescriptor.PERMISSION_WRITE_SIGNED_MITM, "WRITE_SIGNED_MITM");
    }

    private BluetoothAdapter mBlueToothAdapter;
    private BluetoothManager mBluetoothManager;

    private BlueUtils() {
        init();
    }

    public static String getServiceType(int type) {
        return serviceTypes.get(type);
    }

    public static String getCharPermission(int permission) {
        return getHashMapValue(charPermissions, permission);
    }

    public static String getCharPropertie(int property) {
        return getHashMapValue(charProperties, property);
    }

    /**
     * 对外唯一实例的接口
     */
    public static BlueUtils get() {
        return BlueUtils.SingleInstanceHolder.INSTANCE;
    }

    public static String getDescPermission(int property) {
        return getHashMapValue(descPermissions, property);
    }

    private static String getHashMapValue(HashMap<Integer, String> hashMap, int number) {
        String result = hashMap.get(number);
        if (TextUtils.isEmpty(result)) {
            List<Integer> numbers = getElement(number);
            result = "";
            for (int i = 0; i < numbers.size(); i++) {
                result += hashMap.get(numbers.get(i)) + "|";
            }
        }
        return result;
    }

    /**
     * 位运算结果的反推函数10 -> 2 | 8;
     */
    static private List<Integer> getElement(int number) {
        List<Integer> result = new ArrayList<Integer>();
        for (int i = 0; i < 32; i++) {
            int b = 1 << i;
            if ((number & b) > 0)
                result.add(b);
        }

        return result;
    }

    /**
     * 把16进制字符串转换成字节数组
     *
     * @return byte[]
     */
    public static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static int toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }

        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    public static String bytesToHexStringChange(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }

        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }

        return stringBuilder.toString().substring(2, 4) + stringBuilder.toString().substring(0, 2);
    }

    public static String getBits(byte[] src) {
        //瞎改
        StringBuilder stringBuilder = new StringBuilder("");
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toBinaryString(v);
            if (hv.length() < 8) {
                for (int m = 0; m < 8 - hv.length(); m++) {
                    stringBuilder.append(0);
                }
            }
            stringBuilder.append(hv);
            stringBuilder.append("");
        }
        stringBuilder.append("");
        //Device设备获取内容，进行转换
        //LogUtils.e(stringBuilder.toString());
        return stringBuilder.toString();
    }

    //广播包里获取设备编号
    public static String getIdScan(byte[] scanRecord) {
        if (scanRecord.length <= 8) return "";
        if (scanRecord.length < 62) return "";
        try {
            return "" + getBits(new byte[]{scanRecord[7], scanRecord[6], scanRecord[5], scanRecord[4]});
        } catch (Throwable e) {
            LogUtils.e(e);
        }
        return "";
    }

    //广播包里获取设备类型
    public static int getTypeScan(byte[] scanRecord) {
        if (scanRecord.length < 4) return Settings.DATA_TEMP;
        if (scanRecord.length < 62) return Settings.DATA_TEMP;
        try {
            int bcType = Integer.parseInt(getBits(new byte[]{scanRecord[3], scanRecord[2]}), 2);
            return bcType == Settings.DATA_BEAT ? Settings.DATA_BEAT : Settings.DATA_TEMP;
        } catch (Throwable e) {
            LogUtils.e(e);
        }
        return Settings.DATA_TEMP;
    }

    public static String getDataString(byte[] values) {
        if (invalidBytes(values)) {
            return "";
        }
        String alldata = getBits(values);
        if (invalidBits(alldata)) {
            return "";
        }
        return alldata;
    }

    //// TODO:mark 2016/4/28  多少位不确定 应该有个最小值
    public static boolean invalidBits(String alldata) {
        return alldata == null;
//        return alldata == null || alldata.length() !=160;
    }

    // TODO:-mark 2016/4/25 多少位不确定
    public static boolean invalidBytes(byte[] values) {
        return values == null;
//        return values==null || values.length !=20;
    }

    public static List getEcgData(String s) {
        List<Float> list = new ArrayList();
        for (int i = 0; i < NUM_ECG; i++) {
            float rate = getRate(s, i);
            list.add(rate);
        }
        return list;
    }

    public static float getRate(String dataStr, int i) {
        try {
            String rateStr = dataStr.substring(ECG_START + i * ECG_DX, ECG_START + (i + 1) * ECG_DX);
            rateStr = reverseStr(rateStr);
            int tempV = NumUtils.getBinaryIntNum(rateStr);
            float rateVal = getV(tempV);
            return rateVal;
        } catch (Throwable e) {

        }
        return 0f;
    }

    public static String reverseStr(String orginalStr) {
        if (TextUtils.isEmpty(orginalStr)) return "";
        char[] orginalCharArray = orginalStr.toCharArray();
        int start = 0;
        int end = orginalStr.length();
        reverse(orginalCharArray, start, end);
//
//        int n = (end - start)/2;
//        for (int i = 0 ;i< n;i++){
//            char temp = orginalCharArray[start +i];
//            orginalCharArray[start +i] = orginalCharArray[end - i -1];
//            orginalCharArray[end - i - 1] = temp;
//        }
        return new String(orginalCharArray);
    }

    public static void reverse(char[] in, int start, int end) {
        int n = (end - start) / 2;
        for (int i = 0; i < n; i++) {
            char t = in[start + i];
            in[start + i] = in[end - i - 1];
            in[end - i - 1] = t;
        }
    }

    public static float getV(int tempLong) {
//        1.43   4096   1.27
        return Math.round((tempLong * 4.3f / 4096f - 1.27f) * (1000 / 500) * 1000f) / 1000f;
    }

    //取list的前num位
    public static double[] getFirstDataFromList(List<Float> list, int num) {
        double[] temp = new double[num];
        for (int i = 0; i < num; i++) {
            temp[i] = Double.valueOf(list.get(i));
        }
        return temp;
    }

    //取list第from位之后的num位
    public static double[] getDataFromList(List<Float> list, int from, int num) {
        double[] temp = new double[num];
        for (int i = 0; i < num; i++) {
            temp[i] = Double.valueOf(list.get(from + i));
        }
        return temp;
    }

    public static List<Float> transDoubleArrToListFloat(double[] doubleArr) {
        List<Float> list = new ArrayList<>();
        for (Double d : doubleArr) {
            Float f = new Float(d);
            list.add(f);
        }
        return list;
    }

    public static ParsedAd parseData(byte[] adv_data) {
        ParsedAd parsedAd = new ParsedAd();
        ByteBuffer buffer = ByteBuffer.wrap(adv_data).order(ByteOrder.LITTLE_ENDIAN);
        while (buffer.remaining() > 2) {
            byte length = buffer.get();
            if (length == 0)
                break;

            byte type = buffer.get();
            length -= 1;
            switch (type) {
                case 0x01: // Flags
                    parsedAd.flags = buffer.get();
                    length--;
                    break;
                case 0x02: // Partial list of 16-bit UUIDs
                case 0x03: // Complete list of 16-bit UUIDs
                case 0x14: // List of 16-bit Service Solicitation UUIDs
                    while (length >= 2) {
                        parsedAd.uuids.add(UUID.fromString(String.format(
                                "%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));
                        length -= 2;
                    }
                    break;
                case 0x04: // Partial list of 32 bit service UUIDs
                case 0x05: // Complete list of 32 bit service UUIDs
                    while (length >= 4) {
                        parsedAd.uuids.add(UUID.fromString(String.format(
                                "%08x-0000-1000-8000-00805f9b34fb", buffer.getInt())));
                        length -= 4;
                    }
                    break;
                case 0x06: // Partial list of 128-bit UUIDs
                case 0x07: // Complete list of 128-bit UUIDs
                case 0x15: // List of 128-bit Service Solicitation UUIDs
                    while (length >= 16) {
                        long lsb = buffer.getLong();
                        long msb = buffer.getLong();
                        parsedAd.uuids.add(new UUID(msb, lsb));
                        length -= 16;
                    }
                    break;
                case 0x08: // Short local device name
                case 0x09: // Complete local device name
                    byte sb[] = new byte[length];
                    buffer.get(sb, 0, length);
                    length = 0;
                    parsedAd.localName = new String(sb).trim();
                    break;
                case (byte) 0xFF: // Manufacturer Specific Data
                    byte bytes[] = new byte[length];
                    buffer.get(bytes, 0, length);
                    length = 0;
                    parsedAd.manufacturer = new String(bytes).trim();
                    break;
                default: // skip
                    break;
            }
            if (length > 0) {
                buffer.position(buffer.position() + length);
            }
        }
        return parsedAd;
    }

    public BluetoothAdapter getBlueToothAdapter() {
        return mBlueToothAdapter;
    }

    public BluetoothManager getBluetoothManager() {
        return mBluetoothManager;
    }

    /**
     * 初始化数据
     */
    public void init() {
        //蓝牙初始化
        mBluetoothManager = (BluetoothManager) VCare.get().getSystemService(Context.BLUETOOTH_SERVICE);
        mBlueToothAdapter = mBluetoothManager.getAdapter();
        if (mBlueToothAdapter.getState() == BluetoothAdapter.STATE_OFF) {
            mBlueToothAdapter.enable();
        }
        LogUtils.d("Init BlueTooth!");
    }

    /**
     * 静态内部类，实例化对象使用
     */
    private static class SingleInstanceHolder {
        private static final BlueUtils INSTANCE = new BlueUtils();
    }


}
